﻿#region LGPL License

/*
OpenSearchNet
Copyright (c) 2014, Brad Hards <bradh@frogmouth.net>, All rights reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library.
*/

#endregion LGPL License

using System;
using System.Collections.Generic;
using System.Linq;

namespace OpenSearch
{
    /// <summary>
    /// Query template
    /// </summary>
    public class Template
    {
        private string templateAsString;
        private string templateHierPart;
        private char[] queryPartSeparator = { '?' };

        private List<TemplateParameter> templateParameters = new List<TemplateParameter>();

        /// <summary>
        /// Create template from a string representation
        /// </summary>
        /// <param name="templateString">the string that contains the template</param>
        /// <param name="namespaces">dictionary of namespace prefixes and associated namespace</param>
        /// <param name="defaultNamespaceUri">default implicit namespace</param>
        internal Template(string templateString, System.Collections.Generic.IDictionary<string, string> namespaces, string defaultNamespaceUri)
        {
            this.templateAsString = templateString;
            string[] templateparts = templateAsString.Split(queryPartSeparator, 2);
            if (templateparts.Count() != 2)
            {
                return;
            }
            templateHierPart = templateparts[0];
            string templateQueryPart = templateparts[1];
            List<string> templateQueryParts = templateQueryPart.Split('&').ToList<string>();
            foreach (string queryPart in templateQueryParts)
            {
                templateParameters.Add(new TemplateParameter(queryPart, namespaces, defaultNamespaceUri));
            }
        }

        /// <summary>
        /// Add a search term to each template that supports it
        /// </summary>
        /// <param name="queryTerm">the search term to substitute</param>
        /// <remarks>
        /// <para>
        /// The search term is the <c>{searchTerms}</c> parameter. This function will URL encode it.
        /// </para></remarks>
        internal void SubstituteSearchTermInTemplate(string queryTerm)
        {
            foreach (TemplateParameter param in templateParameters)
            {
                // TODO: this should check the namespace as well.
                if ((param.SubstitutionParameterValue != null) && (param.SubstitutionParameterValue.Parameter == "searchTerms"))
                {
                    param.ParameterValue = System.Web.HttpUtility.UrlEncode(queryTerm);
                }
            }
        }

        /// <summary>
        /// Parameters for this template
        /// </summary>
        public IEnumerable<TemplateParameter> TemplateParameters
        {
            get { return templateParameters.AsEnumerable<TemplateParameter>(); }
        }

        /// <summary>
        /// Build the query from a template and the parameters that have been substituted already.
        /// </summary>
        /// <returns>URI ready to use as a web request</returns>
        public Uri InstantiateTemplate()
        {
            // TODO: there should be a template validation first
            // http://192.168.40.180:8181/services/catalog/query?q={searchTerms?}&count={count?}&mt={fs:maxTimeout?}&lat={geo:lat?}&lon={geo:lon?}&radius={geo:radius?}&dtstart={time:start?}&dtend={time:end?}&dtoffset={:offset?}&selector={ddf:selector?}&sort={fs:sort?}&format=atom&type={type?}&version={version?}
            string instantiatedTemplate = templateHierPart + "?";
            bool isFirstParameter = true;
            foreach (TemplateParameter param in templateParameters)
            {
                if (param.ParameterValue != null)
                {
                    if (!isFirstParameter)
                    {
                        instantiatedTemplate += "&";
                    }
                    instantiatedTemplate += (param.Name + "=" + param.ParameterValue);
                    isFirstParameter = false;
                }
            }
            return new Uri(instantiatedTemplate);
        }

        /// <summary>
        /// Get the template as a string
        /// </summary>
        /// <returns>string representation of the template</returns>
        public override string ToString()
        {
            // TODO: this should really rebuild the template
            return templateAsString;
        }
    }
}